package com.kitty.common.db;


import com.kitty.cross.CrossServerConfig;
import com.kitty.game.player.PlayerService;
import com.kitty.game.role.model.Role;
//import com.kitty.common.utils.SpringUtils;
import com.kitty.common.thread.NamedThreadFactory;
import com.kitty.common.utils.BlockingUniqueQueue;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.nutz.dao.Dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;





/**
 * 玩家数据持久化队列
 */
@Component
@Slf4j
public class Db4PlayerService {

    private static volatile Db4PlayerService instance;
    @Autowired
    CrossServerConfig crossServerConfig;
    @Autowired
    PlayerService playerService;

    @Autowired
    private Dao dao;

    public static Db4PlayerService getInstance() {
        return instance;
    }

    /**
     * start consumer thread
     */
    @PostConstruct
    private void init() {
        new NamedThreadFactory("db-player-save-service").newThread(new Worker()).start();
        instance = this;
    }

    private BlockingQueue<Role> queue = new BlockingUniqueQueue<>();

    private final AtomicBoolean run = new AtomicBoolean(true);

    public void add2Queue(Role entity) {
        // 跨服不保存玩家数据
        if (crossServerConfig.isCenterServer()) {
            return;
        }
        this.queue.add(entity);
        playerService.saveToCache(entity);
        //log.error("入库队列大小==={}",queue.size());
    }

    public int size() {
        return this.queue.size();
    }

    private class Worker implements Runnable {
        @Override
        public void run() {
            while (run.get()) {
                Role entity = null;
                try {
                    entity = queue.take();
                    StopWatch stopWatch = new StopWatch();
                    stopWatch.start();
                    saveToDb(entity);
                    stopWatch.stop();
                    if (stopWatch.getTime() > 500) {
                        log.error("玩家数据持久化消耗毫秒：" + stopWatch.getTime());
                        log.error("玩家数据持久化队列长度：" + queue.size());
                    }
                } catch (Exception e) {
                    log.error("", e);
                    // 有可能是并发抛错，重新放入队列
                    add2Queue(entity);
                }
            }
        }
    }

    /**
     * 数据真正持久化
     *
     * @param entity
     */
    private void saveToDb(Role entity) {
        playerService.saveToCache(entity);
        entity.doBeforeSave();
        if (entity.isDelete()) {
            dao.delete(entity);
        } else {
            dao.insertOrUpdate(entity);
        }
    }

    @PreDestroy
    public void shutDown() {
        run.getAndSet(false);
        for (; ;) {
            if (! queue.isEmpty()) {
                saveAllBeforeShutDown();
            } else {
                break;
            }
        }
        log.error("[db4Player] 执行全部命令后关闭");
    }

    private void saveAllBeforeShutDown() {
        while (!queue.isEmpty()) {
            Iterator<Role> it = queue.iterator();
            while (it.hasNext()) {
                Role player = it.next();
                it.remove();
                saveToDb(player);
            }
        }
    }

}